/**
@file
	PerfCounter.h
@brief

@author
	GengYong
@revision
	2005/11/05 * Created by GengYong.
*/


#ifndef SAF_HEADER_FILE_PERFCOUNTER_H
#define SAF_HEADER_FILE_PERFCOUNTER_H

#if (defined(_DEBUG) || !defined(DISABLE_PERFCOUNTER))
#	define ENABLE_PERFCOUNTER
#endif

#ifdef ENABLE_PERFCOUNTER
#	define REGISTER_PERFCOUNTER(name)	SAF::PerfProfileManager::Instance().SetProjectName(name);
#	define PERFCOUNTER(name)														\
		static struct CounterHandler{												\
			SAF::PerfProfileManager::PerfProfile * profile;							\
			CounterHandler(const char * iden){										\
				profile = SAF::PerfProfileManager::Instance().AllocProfile(iden);	\
			}																		\
			~CounterHandler(){														\
				SAF::PerfProfileManager::Instance().FreeProfile(profile);			\
			}																		\
		} _static_counter_(#name);													\
		struct PerfCounter{															\
			PerfCounter(){															\
			_static_counter_.profile->called++;										\
			startTick = SAF::PerfGetTick();											\
			}																		\
			~PerfCounter(){															\
			_static_counter_.profile->usedtick += SAF::PerfGetTick()-startTick;		\
			}																		\
		private:																	\
			unsigned long long	startTick;											\
		} _local_perfCounter_;

#include <ctime>
#include <string>

	//=============================================================
	// PerfCounter Begin here
	//=============================================================
	namespace SAF
	{
		inline unsigned long long PerfGetTick()
		{
#		if defined(WIN32)
			__asm rdtsc;
#		else
			unsigned long long cycle;
			__asm__ __volatile__ ("rdtsc" : "=A"(cycle)); 
			return cycle;
#		endif
		}

		class PerfProfileManager
		{
		public:
			class PerfProfile
			{
			public:
				std::string			idenity;
				unsigned long long	called;
				unsigned long long	usedtick;
				PerfProfile *		leaf;
				PerfProfile *		next;
			public:
				PerfProfile(const std::string& iden): idenity(iden), called(0), usedtime(0), leaf(0), next(0)
				{
					return;
				}
				~PerfProfile()
				{
					if (next != NULL)
					{
						delete next;
						next = NULL;
					}
					if (leaf != NULL)
					{
						delete leaf;
						leaf = NULL;
					}
					return;
				}
			};
		public:
			static PerfProfileManager& Instance()
			{
				static PerfProfileManager instance;
				return instance;
			}
		public:
			void SetProjectName(const std::string& name)
			{
				projectName = name;
				return;
			}
		public:
			PerfProfile * AllocProfile(const std::string& iden)
			{
				if (profileTail != NULL)
				{
					profileTail->next = new PerfProfile(iden);
					profileTail = profileTail->next;
				}
				else
				{
					profileHead = profileTail = new PerfProfile(iden);
				}
				return profileTail;
			}
			void FreeProfile(PerfProfile *)
			{
				return;
			}
		private:
			PerfProfileManager():projectName(0), profileHead(0), profileTail(0)
			{
				startTime = time(NULL);
				startTick = PerfGetTick();
				return;
			}

			~PerfProfileManager()
			{
				unsigned long long totalTicks = PerfGetTick() - startTick;
				time_t duration = time(NULL) - startTime;
				printf("==============================================================================\n");
				printf("Running time: %llu million ticks in %llu seconds - [%s]\n",
					(unsigned long long)(totalTicks/1,000,000), (unsigned long long)(duration), (projectName == NULL? "unknown":projectName));
				printf("------------------------------------------------------------------------------\n");
				printf("           ticks     called   ratio(%%)        average   name\n");
				printf("------------------------------------------------------------------------------\n");
				for (PerfProfileManager::PerfProfile * point = profileHead; point != NULL; point = point->next)
				{
#		if defined(WIN32)
					printf("%16I64u %10I64u   %8.4lf %14I64u   %s\n", 
#		else
					printf("%16llu %10llu   %8.4lf %14llu   %s\n",
#endif
						point->usedtime, point->called,
						(totalTicks == 0 ? (double)(0.0f) : (double)point->usedtick/(double)(totalTicks) * 100.0f),
						(point->called == 0 ? 0:point->usedtime/point->called),
						point->idenity);
					
				}
				printf("==============================================================================\n");

				if (profileHead != NULL)
				{
					delete profileHead;
					profileHead = profileTail = NULL;
				}
				return;
			}
		private:
			unsigned long long	startTick;
			time_t				startTime;
			std::string			projectName;
			PerfProfile *		profileHead;
			PerfProfile *		profileTail;
		};
	}

#else
#	define REGISTER_PERFCOUNTER(name)
#	define PERFCOUNTER(name)
#endif

#endif	//#ifndef SAF_HEADER_FILE_PERFCOUNTER_H
